package com.atguigu.springcloud.cloudsentinelgatewaydevelop.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.DO.SentinelAuthorityRuleDO;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.dto.SentinelAuthorityRuleDTO;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.constants.TableNameConstants;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.mapper.AuthorityRuleMapper;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.service.AuthorityRuleService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.r2dbc.spi.ConnectionFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;

import static org.springframework.data.r2dbc.query.Criteria.where;

/**
 * xxx
 *
 * @author BugFree Jin
 * @version 1.0
 * @since 2022/3/2 16:27
 */
@Service
@RequiredArgsConstructor
public class AuthorityRuleServiceImpl implements AuthorityRuleService {

    private final AuthorityRuleMapper authorityRuleMapper;

    private final ConnectionFactory connectionFactory;

    DatabaseClient client = null;

    @PostConstruct
    void init() {
        this.client = DatabaseClient.create(connectionFactory);
    }

    // DTO2DO
    private SentinelAuthorityRuleDO  copyField(SentinelAuthorityRuleDTO sentinelAuthorityRuleDTO) {
        SentinelAuthorityRuleDO sentinelAuthorityRuleDO = new SentinelAuthorityRuleDO();
        SentinelAuthorityRuleDO.AuthorityRule authorityRule = new SentinelAuthorityRuleDO.AuthorityRule();
        BeanUtils.copyProperties(sentinelAuthorityRuleDTO, sentinelAuthorityRuleDO, "authority_rule");
        BeanUtils.copyProperties(sentinelAuthorityRuleDTO, authorityRule);
        String authoritRuleStr = null;
        try {
            authoritRuleStr = new ObjectMapper().writeValueAsString(authorityRule);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        sentinelAuthorityRuleDO.setAuthorityRule(authoritRuleStr);
        return sentinelAuthorityRuleDO;
    }

    @Override
    public Mono<Integer> save(SentinelAuthorityRuleDTO sentinelAuthorityRuleDTO) {
        SentinelAuthorityRuleDO sentinelAuthorityRuleDO = copyField(sentinelAuthorityRuleDTO);

        return client.insert()
                .into(TableNameConstants.AUTHORITYRULE)
                .nullValue("id", Long.class)
                .value("application_name", sentinelAuthorityRuleDO.getApplicationName())
                .value("resource", sentinelAuthorityRuleDO.getResource())
                .value("authority_rule", sentinelAuthorityRuleDO.getAuthorityRule())
                .fetch()
                .rowsUpdated();
    }

    @Override
    public Mono<Integer> deleteById(Long id) {
        return authorityRuleMapper.deleteByID(id);
    }

    @Override
    public Mono<Integer> deleteByAyApplicationName(String applicationName) {
        return authorityRuleMapper.deleteByAyApplicationName(applicationName);
    }

    @Override
    public Mono<Integer> updateById(SentinelAuthorityRuleDTO sentinelAuthorityRuleDTO, Long id) {
        SentinelAuthorityRuleDO sentinelAuthorityRuleDO = new SentinelAuthorityRuleDO();
        SentinelAuthorityRuleDO.AuthorityRule authorityRule = new SentinelAuthorityRuleDO.AuthorityRule();
        BeanUtils.copyProperties(authorityRule, sentinelAuthorityRuleDTO);
        BeanUtils.copyProperties(sentinelAuthorityRuleDTO, sentinelAuthorityRuleDO);
        sentinelAuthorityRuleDO.setAuthorityRule(JSON.toJSONString(authorityRule));

        return client.update()
                .table(SentinelAuthorityRuleDO.class)
                .using(sentinelAuthorityRuleDO)
                .matching(where("id").is(id))
                .fetch()
                .rowsUpdated();
    }

    @Override
    public Mono<SentinelAuthorityRuleDTO> findById(Long id) {
        return client.select()
                .from(TableNameConstants.AUTHORITYRULE)
                .matching(where("id").is(id))
                .as(SentinelAuthorityRuleDO.class)
                .fetch()
                .one()
                .map(SentinelAuthorityRuleDO::getSentinelAuthorityRuleDTO)
                .log();
    }

    @Override
    public Flux<SentinelAuthorityRuleDTO> findByApplicationName(String applicationName) {
        return client.select()
                .from(TableNameConstants.AUTHORITYRULE)
                .matching(where("application_name").is(applicationName))
                .as(SentinelAuthorityRuleDO.class)
                .fetch()
                .all()
                .map(SentinelAuthorityRuleDO::getSentinelAuthorityRuleDTO)
                .log();
    }
}
